package com.xwj.coupon.user.repository.redis;

import cn.hutool.core.bean.BeanUtil;
import com.xwj.coupon.user.common.constant.MerchantAdminRedisConstant;
import com.xwj.coupon.user.dto.resp.CouponTemplateQueryRespDTO;
import com.xwj.coupon.user.repository.mysql.entity.CouponTemplateDO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Component;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Author: XuWenjie
 * @Date: 2025-08-14
 * @Description: CouponTemplateDao
 */
@Component
@Slf4j
public class CouponTemplateDao {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    private final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    private final String redisKeyPrefix = MerchantAdminRedisConstant.COUPON_TEMPLATE_KEY;
    public CouponTemplateDO getCouponTemplateById(Long couponTemplateId){
        // 获取Hash中所有字段和值
        String couponTemplateCacheKey = String.format(redisKeyPrefix, couponTemplateId);
        Map<Object, Object> fields = stringRedisTemplate.opsForHash().entries(couponTemplateCacheKey);

        if (fields.isEmpty()) {
            log.info("优惠券模板{}不存在",couponTemplateId);
            return null;
        }

        // 转换为CouponTemplateDO对象
        return mapToCouponTemplate(fields);
    }

    /**
     * 使用Pipeline批量获取多个键的值
     */
    public List<CouponTemplateDO> batchGetCouponTemplateWithPipeline(List<Long> ids) {
        List<String> keys = ids.stream().map(id -> String.format(redisKeyPrefix, id)).toList();
        // 使用Pipeline批量查询所有Hash结构
        List<Object> results = stringRedisTemplate.executePipelined(
                (RedisCallback<Object>) connection -> {
                    for (String key : keys) {
                        // 向管道中添加HGETALL命令
                        connection.hGetAll(key.getBytes());
                    }
                    // 必须返回null，否则会被当作命令执行
                    return null;
                }
        );

        // 处理查询结果
        List<CouponTemplateDO> templates = new ArrayList<>(results.size());
        for (Object result : results) {
            if (result instanceof Map) {
                // 转换为CouponTemplateDO对象
                @SuppressWarnings("unchecked")
                Map<Object, Object> fields = (Map<Object, Object>) result;
                if (!fields.isEmpty()) {
                    templates.add(mapToCouponTemplate(fields));
                }
            }
        }

        return templates;

    }

    /**
     * 将Hash字段映射为CouponTemplateDO对象（全字段判空处理）
     */
    private CouponTemplateDO mapToCouponTemplate(Map<Object, Object> fields) {
        CouponTemplateDO template = new CouponTemplateDO();

        try {
            // Long类型字段 - 判空处理
            if (fields.get("id") != null) {
                template.setId(Long.parseLong(fields.get("id").toString()));
            }
            if (fields.get("shopNumber") != null) {
                template.setShopNumber(Long.parseLong(fields.get("shopNumber").toString()));
            }
            if (fields.get("promotionValue") != null) {
                template.setPromotionValue(Long.parseLong(fields.get("promotionValue").toString()));
            }

            // Integer类型字段 - 判空处理
            if (fields.get("source") != null) {
                template.setSource(Integer.parseInt(fields.get("source").toString()));
            }
            if (fields.get("target") != null) {
                template.setTarget(Integer.parseInt(fields.get("target").toString()));
            }
            if (fields.get("type") != null) {
                template.setType(Integer.parseInt(fields.get("type").toString()));
            }
            if (fields.get("stock") != null) {
                template.setStock(Integer.parseInt(fields.get("stock").toString()));
            }
            if (fields.get("status") != null) {
                template.setStatus(Integer.parseInt(fields.get("status").toString()));
            }
            if (fields.get("delFlag") != null) {
                template.setDelFlag(Integer.parseInt(fields.get("delFlag").toString()));
            }
            if (fields.get("bottomPrice") != null) {
                template.setBottomPrice(Integer.parseInt(fields.get("bottomPrice").toString()));
            }
            if (fields.get("fetchLimit") != null) {
                template.setFetchLimit(Integer.parseInt(fields.get("fetchLimit").toString()));
            }

            // 字符串类型字段 - 直接赋值（允许null）
            template.setName(fields.get("name") != null ? fields.get("name").toString() : null);
            template.setGoods(fields.get("goods") != null ? fields.get("goods").toString() : null);
            template.setReceiveRule(fields.get("receiveRule") != null ? fields.get("receiveRule").toString() : null);
            template.setConsumeRule(fields.get("consumeRule") != null ? fields.get("consumeRule").toString() : null);

            // 日期类型字段 - 判空处理
            if (fields.get("validStartTime") != null) {
                template.setValidStartTime(sdf.parse(fields.get("validStartTime").toString()));
            }
            if (fields.get("validEndTime") != null) {
                template.setValidEndTime(sdf.parse(fields.get("validEndTime").toString()));
            }
            if (fields.get("fetchStartTime") != null) {
                template.setFetchStartTime(sdf.parse(fields.get("fetchStartTime").toString()));
            }
            if (fields.get("fetchEndTime") != null) {
                template.setFetchEndTime(sdf.parse(fields.get("fetchEndTime").toString()));
            }
            if (fields.get("createTime") != null) {
                template.setCreateTime(sdf.parse(fields.get("createTime").toString()));
            }
            if (fields.get("updateTime") != null) {
                template.setUpdateTime(sdf.parse(fields.get("updateTime").toString()));
            }

        } catch (ParseException e) {
            throw new RuntimeException("日期格式转换错误: " + e.getMessage(), e);
        } catch (NumberFormatException e) {
            throw new RuntimeException("数字格式转换错误: " + e.getMessage(), e);
        }

        return template;
    }

    public void incrementStock(Long templateId, int increment) {
        String hashKey = String.format(redisKeyPrefix,templateId);
        stringRedisTemplate.opsForHash().increment(hashKey, "stock", increment);
    }
    /**
     * 获取Hash中的单个字段值
     */
    public String getHashField(Long templateId, String field) {
        String hashKey = String.format(redisKeyPrefix,templateId);
        return (String) stringRedisTemplate.opsForHash().get(hashKey, field);
    }

    /**
     * 更新Hash中的单个字段
     */
    public void updateHashField(Long templateId, String field, String value) {
        String hashKey = String.format(redisKeyPrefix,templateId);
        stringRedisTemplate.opsForHash().put(hashKey, field, value);
    }

    public void setCouponTemplate(CouponTemplateDO couponTemplateDO) {
        // 缓存预热：通过将数据库的记录序列化成 JSON 字符串放入 Redis 缓存
        CouponTemplateQueryRespDTO actualRespDTO = BeanUtil.toBean(couponTemplateDO, CouponTemplateQueryRespDTO.class);
        Map<String, Object> cacheTargetMap = BeanUtil.beanToMap(actualRespDTO, false, true);
        Map<String, String> actualCacheTargetMap = cacheTargetMap.entrySet().stream()
                .collect(Collectors.toMap(
                        Map.Entry::getKey,
                        entry -> entry.getValue() != null ? entry.getValue().toString() : ""
                ));
        String couponTemplateCacheKey = String.format(MerchantAdminRedisConstant.COUPON_TEMPLATE_KEY, couponTemplateDO.getId());

        // 通过 LUA 脚本执行设置 Hash 数据以及设置过期时间
        final String luaScript = "redis.call('HMSET', KEYS[1], unpack(ARGV, 1, #ARGV - 1)) " +
                "redis.call('EXPIREAT', KEYS[1], ARGV[#ARGV])";

        List<String> keys = Collections.singletonList(couponTemplateCacheKey);
        List<String> args = new ArrayList<>(actualCacheTargetMap.size() * 2 + 1);
        actualCacheTargetMap.forEach((key, value) -> {
            args.add(key);
            args.add(value);
        });

        // 优惠券活动过期时间转换为秒级别的 Unix 时间戳
        args.add(String.valueOf(couponTemplateDO.getValidEndTime().getTime() / 1000));

        log.info("优惠券模板缓存新增/更新keys：{}", keys);
        log.info("优惠券模板缓存新增/更新args：{}", args);
        // 执行 LUA 脚本
        stringRedisTemplate.execute(
                new DefaultRedisScript<>(luaScript, Long.class),
                keys,
                args.toArray()
        );
    }
}
